﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;

namespace SHomeWorkshop.LunarTools
{
    public static class PointToRect
    {
        /// <summary>
        /// 求一个点与矩形中心点的连线与矩形的边缘的交点。
        /// </summary>
        /// <param name="rect">矩形</param>
        /// <param name="point">矩形内部或外部一点。</param>
        /// <returns></returns>
        public static ArrowPoints GetCrossPointToRect(Rect rect, Point point)
        {
            Point center = new Point(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2);

            ArrowPoints arrowPt = new ArrowPoints();
            double arrowHeight = 10;

            if (point.X == center.X)
            {
                if (point.Y < center.Y)//y轴正向。
                {

                    arrowPt.Top = new Point(center.X, rect.Top);
                    arrowPt.Start = new Point(center.X + arrowHeight / Math.Sqrt(3), rect.Top - arrowHeight);
                    arrowPt.End = new Point(center.X - arrowHeight / Math.Sqrt(3), rect.Top - arrowHeight);
                    return arrowPt;
                }
                else if (point.Y == center.Y)//正好是Rect中心。这几乎不可能出现。
                {
                    //为防止出现这一情况。

                    point.X += 1; point.Y += 1;

                    //arrowPt.Top = center;
                    //arrowPt.Start = center;
                    //arrowPt.End = center;
                    //return arrowPt;
                }
                else if (point.Y > center.Y)//y轴负向。
                {

                    arrowPt.Top = new Point(center.X, rect.Bottom);
                    arrowPt.Start = new Point(center.X - arrowHeight / Math.Sqrt(3), rect.Bottom + arrowHeight);
                    arrowPt.End = new Point(center.X + arrowHeight / Math.Sqrt(3), rect.Bottom + arrowHeight);
                    return arrowPt;
                }
            }

            if (point.Y == center.Y)
            {
                if (point.X > center.X)
                {

                    arrowPt.Top = new Point(rect.Right, center.Y);//X轴正向。
                    arrowPt.Start = new Point(rect.Right + arrowHeight, center.Y + arrowHeight / Math.Sqrt(3));
                    arrowPt.End = new Point(rect.Right + arrowHeight, center.Y - arrowHeight / Math.Sqrt(3));
                    return arrowPt;
                }
                else//point.X==0且point.Y==0已经返回，此处必定是point.X<0。
                {

                    arrowPt.Top = new Point(rect.Left, center.Y);//X轴负向。
                    arrowPt.Start = new Point(rect.Left - arrowHeight, center.Y - arrowHeight / Math.Sqrt(3));
                    arrowPt.End = new Point(rect.Left - arrowHeight, center.Y + arrowHeight / Math.Sqrt(3));
                    return arrowPt;
                }
            }
            //下面无须再考虑特殊情况（正好在某轴上）了。

            Quadrant qua;
            if (point.X > center.X)
            {
                if (point.Y < center.Y)
                    qua = Quadrant.First;
                else
                    qua = Quadrant.Fourth;
            }
            else
            {
                if (point.Y < center.Y)
                    qua = Quadrant.Second;
                else
                    qua = Quadrant.Third;
            }

            double l = arrowHeight / Math.Sqrt(3);//三角形底边长度的一半。

            switch (qua)
            {
                case Quadrant.First:
                    {
                        double tmp = (center.Y - point.Y) / (point.X - center.X) - (center.Y - rect.TopRight.Y) / (rect.Right - center.X);

                        if (tmp == 0)
                        {
                            arrowPt.Top = rect.TopRight;
                        }
                        else if (tmp > 0)//在第一象限以矩形中心到对角线的上半部分。这部分已经所求的y值。
                        {
                            arrowPt.Top = new Point(center.X + (point.X - center.X) / (center.Y - point.Y) * (center.Y - rect.Top), rect.Top);
                        }
                        else//tmp<0在第一象限下半部分，已经X
                        {
                            arrowPt.Top = new Point(rect.Right, center.Y - (center.Y - point.Y) / (point.X - center.X) * (rect.Right - center.X));
                        }

                        //double tan = arrowPt.Top.Y - center.Y / arrowPt.Top.X - center.X;
                        double sin = (center.Y - arrowPt.Top.Y) / Math.Sqrt(Math.Pow(center.Y - arrowPt.Top.Y, 2) + Math.Pow(arrowPt.Top.X - center.X, 2));
                        double cos = Math.Sqrt(1 - sin * sin);

                        Point ptTmp = new Point(arrowPt.Top.X + arrowHeight * cos, arrowPt.Top.Y - arrowHeight * sin);

                        arrowPt.Start = new Point(ptTmp.X - l * sin, ptTmp.Y - l * cos);
                        arrowPt.End = new Point(ptTmp.X + l * sin, ptTmp.Y + l * cos);

                        return arrowPt;
                    }
                case Quadrant.Second:
                    {
                        double tmp = (center.Y - point.Y) / (center.X - point.X) - (center.Y - rect.Top) / (center.X - rect.Left);

                        if (tmp == 0)
                        {
                            arrowPt.Top = rect.TopLeft;
                        }
                        else if (tmp > 0)//第二象限上半部分。已知y值。
                        {
                            arrowPt.Top = new Point(center.X - (center.Y - rect.Top) * (center.X - point.X) / (center.Y - point.Y), rect.Top);
                        }
                        else //tmp<0,第二象限下半部分。已知X值。
                        {
                            arrowPt.Top = new Point(rect.Left, center.Y - (center.X - rect.Left) * (center.Y - point.Y) / (center.X - point.X));
                        }

                        //double tan = arrowPt.Top.Y - center.Y / arrowPt.Top.X - center.X;
                        double sin = (center.Y - arrowPt.Top.Y) / Math.Sqrt(Math.Pow(arrowPt.Top.Y - center.Y, 2) + Math.Pow(center.X - arrowPt.Top.X, 2));
                        double cos = Math.Sqrt(1 - sin * sin);

                        Point ptTmp = new Point(arrowPt.Top.X - arrowHeight * cos, arrowPt.Top.Y - arrowHeight * sin);

                        arrowPt.Start = new Point(ptTmp.X - l * sin, ptTmp.Y + l * cos);
                        arrowPt.End = new Point(ptTmp.X + l * sin, ptTmp.Y - l * cos);

                        return arrowPt;
                    }
                case Quadrant.Third:
                    {
                        double tmp = (point.Y - center.Y) / (center.X - point.X) - (rect.Bottom - center.Y) / (center.X - rect.Left);

                        if (tmp == 0)
                        {
                            arrowPt.Top = rect.BottomLeft;
                        }
                        else if (tmp > 0)//第三象限下半部分，已知y值。
                        {
                            arrowPt.Top = new Point(center.X - (rect.Bottom - center.Y) * (center.X - point.X) / (point.Y - center.Y), rect.Bottom);
                        }
                        else//tmp第三象限上半部分。已知Ｘ值。
                        {
                            arrowPt.Top = new Point(rect.Left, center.Y + ((center.X - rect.Left) * (point.Y - center.Y) / (center.X - point.X)));
                        }

                        //double tan = arrowPt.Top.Y - center.Y / arrowPt.Top.X - center.X;
                        double sin = (arrowPt.Top.Y - center.Y) / Math.Sqrt(Math.Pow(arrowPt.Top.Y - center.Y, 2) + Math.Pow(center.X - arrowPt.Top.X, 2));
                        double cos = Math.Sqrt(1 - sin * sin);

                        Point ptTmp = new Point(arrowPt.Top.X - arrowHeight * cos, arrowPt.Top.Y + arrowHeight * sin);

                        arrowPt.Start = new Point(ptTmp.X - l * sin, ptTmp.Y - l * cos);
                        arrowPt.End = new Point(ptTmp.X + l * sin, ptTmp.Y + l * cos);

                        return arrowPt;
                    }
                case Quadrant.Fourth:
                    {
                        double tmp = (point.Y - center.Y) / (point.X - center.X) - (rect.Bottom - center.Y) / (rect.Right - center.X);

                        if (tmp == 0)
                        {
                            arrowPt.Top = rect.BottomRight;
                        }
                        else if (tmp > 0)//在第四象限下半部分。已知y。
                        {
                            arrowPt.Top = new Point(center.X + ((rect.Bottom - center.Y) * (point.X - center.X) / (point.Y - center.Y)), rect.Bottom);
                        }
                        else//tmp<0,已知Ｘ值。
                        {
                            arrowPt.Top = new Point(rect.Right, center.Y + ((rect.Right - center.X) * (point.Y - center.Y) / (point.X - center.X)));
                        }

                        //double tan = arrowPt.Top.Y - center.Y / arrowPt.Top.X - center.X;
                        double sin = (arrowPt.Top.Y - center.Y) / Math.Sqrt(Math.Pow(arrowPt.Top.Y - center.Y, 2) + Math.Pow(center.X - arrowPt.Top.X, 2));
                        double cos = Math.Sqrt(1 - sin * sin);

                        Point ptTmp = new Point(arrowPt.Top.X + arrowHeight * cos, arrowPt.Top.Y + arrowHeight * sin);

                        arrowPt.Start = new Point(ptTmp.X - l * sin, ptTmp.Y + l * cos);
                        arrowPt.End = new Point(ptTmp.X + l * sin, ptTmp.Y - l * cos);

                        return arrowPt;
                    }
            }
            return null;//除非出错，不会走到这个分支。
        }

        /// <summary>
        /// 四象限。
        /// </summary>
        public enum Quadrant { First, Second, Third, Fourth }

        public class ArrowPoints
        {
            /// <summary>
            /// 箭头的端点。决定箭头的指向。在绘制折线时，这点是第二个点。
            /// </summary>
            public Point Top { get; set; }

            /// <summary>
            /// 箭头的两边端点之一。因折线从这里开始绘制，故名。
            /// </summary>
            public Point Start { get; set; }

            /// <summary>
            /// 箭头的两边端点之一。折线绘制到这点结束。
            /// </summary>
            public Point End { get; set; }
        }
    }
}
